# 用户登录
import base64
import os
import re
import time
import datetime
import json
from os import urandom

from flask_jwt_extended import create_access_token
from flask import (
    g, Blueprint, current_app, redirect, render_template, request, send_from_directory, url_for, jsonify
)

from flask_wtf import FlaskForm
from wtforms import (
    StringField, 
    SubmitField
)
from wtforms.validators import (
    DataRequired, 
    EqualTo, 
    ValidationError
)
from werkzeug.security import (
    generate_password_hash,
    check_password_hash
)

from app import db,redis_client
from app.models import User, UserInfo, UserInfoSchema

auth_bp = Blueprint('auth', __name__, url_prefix = '/auth')

# 序列化对象
user_info_schema = UserInfoSchema()

class RegisterForm(FlaskForm):
    '''
    场景: 需要验证用户输入 ( 如注册、登录、数据提交 ) 时, FlaskForm 通过 WTForms 的验证器 (Validators)自动检查数据合法性。
    '''
    # StringField：文本输入字段​ 1. 作用：生成文本输入字段，用户输入数据保存为字段值 2. 渲染效果​：前端渲染为 <input type="text">
    # 参数：label：字段的显示标签（如 '用户名'），validators：字段的验证器，如 DataRequired()

    username = StringField('用户名', validators=[DataRequired()]) # DataRequired() 不能为空
    password = StringField('密码', validators=[DataRequired()])
    confirm_password = StringField('确认密码', validators=[DataRequired(), EqualTo('password', '密码不一致')]) # EqualTo() 验证字段值是否相等   

    # SubmitField：表单提交按钮​ 1. 作用：生成表单的提交按钮，用户点击后触发表单验证与数据提交 2. 渲染效果​：前端渲染为 <input type="submit">，点击后执行 form.validate_on_submit() 逻辑
    submit = SubmitField('注册')

    # 自定义验证函数，命名规范validate_<字段名> -- > 字段名 等价于 field.data 
    def validate_username(self, field):
        print(field.data)
        user = User.query.filter_by(user_name=field.data).first() # field:
        if user:
            raise ValidationError('该用户名已被注册')
'''
完整表单验证流程​:
    1. ​提交触发​：用户点击 SubmitField 按钮。
    2. ​内置验证​：自动执行 validators 中的规则（如非空检查、密码一致性）。
    3. ​自定义验证​：若内置验证通过，自动调用 validate_字段名 函数。
    ​4. 结果处理​：
        a. 所有验证通过 → 执行 form.validate_on_submit() 中的逻辑（如保存数据）。
        b. 验证失败 → 在模板中通过 form.字段名.errors 显示错误信息。
'''

@auth_bp.route('/login', methods=['POST'])
def login():
    ### 登录 ###
    username = request.form['username']
    password = request.form['password']

    user = User.query.filter_by(user_name=username).first()
    # 将password进行hash加密, 然后与数据库存储的password进行比较（此时认为数据库存储的是加密后的hash密码）
    if user and check_password_hash(user.password, password):
        userInfo = UserInfo.query.filter_by(id=user.id).first()
         
        user_data_dict = user_info_schema.dump(userInfo) # 调用对象的dump方法，将userInfo对象转换为字典
        user_data_json = json.dumps(user_data_dict, ensure_ascii=False) #  ensure_ascii=False 保证输出的JSON是UTF-8编码，而不是ASCII编码 # 使用 json.dumps() 将字典转换为 JSON 格式的字符串
        ''' user_data_json 是字符串类型'''

        # 生成 JWT（标准方案）
        access_token = create_access_token(
            identity=str(user.id),  # 标准字段 identity 代替 sub/id, @jwt_required()内部验证逻辑要求为字符串，不然会报422类型错误
            expires_delta=datetime.timedelta(days=7),
        )
        # 加载进redis，表示已经登录
        redis_client.setex(f'user:{user.id}', 3600, user_data_json) # 只能存储字符串类型（json 类型）
        '''
        f'user:{user_id}'：缓存键（推荐用业务前缀+ID）
        3600：过期时间（按需调整）
        user_data_json：JSON序列化后的数据
        '''
        return jsonify({
            'status' : 'success',
            'access_token' : access_token,
            'redirect_url' : url_for('web.profile')
        }
        ), 200 # 明确状态码
    else:
        return jsonify({
            'status':'fail',
            'message':'用户名或密码错误'
        }), 401
  

@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
    ### 注册 ###
    form = RegisterForm()
    if request.method == 'POST':
        if form.validate_on_submit():
            username = request.form['username']
            password = request.form['password']
            hash_password = generate_password_hash(password)

            user = User(user_name=username, password=hash_password)
            db.session.add(user)
            db.session.commit()
            print('注册成功')
            # 添加个人信息
            userinfo = UserInfo(id=user.id, nickname='User' + urandom(10).hex()[:10])
            db.session.add(userinfo)
            db.session.commit()
            print('添加个人信息成功')
            return redirect(url_for('auth.login'))
        else:
            print(form.csrf_token.current_token)
            return render_template('auth/register.html', form = form)
    return render_template('auth/register.html', form = form) # form: 表单对象, 将定义的表单对象传递给模板，模板中通过 {{ form.字段名 }} 访问字段对象


        

